home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / gdb / foo / xgdb.c < prev   
Encoding:
C/C++ Source or Header  |  1990-01-10  |  15.6 KB  |  612 lines

  1. /* Interface from GDB to X windows.
  2.    Copyright (C) 1987, 1989 Free Software Foundation, Inc.
  3.  
  4. This file is part of GDB.
  5.  
  6. GDB is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 1, or (at your option)
  9. any later version.
  10.  
  11. GDB is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with GDB; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. /* Original version was contributed by Derek Beatty, 30 June 87.  */
  21.  
  22. #include <stdio.h>
  23. #include "defs.h"
  24. #include "param.h"
  25. #include "symtab.h"
  26. #include "frame.h"
  27.  
  28. #include <X11/IntrinsicP.h>
  29. #include <X11/StringDefs.h>
  30. #include <X11/Label.h>
  31. #include <X11/Command.h>
  32. #include <X11/AsciiText.h>
  33. #include <X11/Box.h>
  34. #include <X11/VPaned.h>
  35.  
  36.  
  37. /*#define    XtNfunction    "function"*/
  38.  
  39. /* Cursor used in GDB window.  */
  40.  
  41. #define gdb_width 16
  42. #define gdb_height 16
  43. #define gdb_x_hot 7
  44. #define gdb_y_hot 0
  45. static short gdb_bits[] = {
  46.    0x0000, 0x0140, 0x0220, 0x0220,
  47.    0x23e2, 0x13e4, 0x09c8, 0x0ff8,
  48.    0x0220, 0x3ffe, 0x0630, 0x03e0,
  49.    0x0220, 0x1ffc, 0x2632, 0x01c0};
  50.  
  51. #define gdb_mask_width 16
  52. #define gdb_mask_height 16
  53. #define gdb_mask_x_hot 7
  54. #define gdb_mask_y_hot 0
  55. static short gdb_mask_bits[] = {
  56.    0x0360, 0x07f0, 0x07f0, 0x77f7,
  57.    0x7fff, 0x7fff, 0x1ffc, 0x1ffc,
  58.    0x7fff, 0x7fff, 0x7fff, 0x0ff8,
  59.    0x3ffe, 0x7fff, 0x7fff, 0x7fff};
  60.  
  61. /* The X display on which the window appears.  */
  62.  
  63. Display *screen_display;
  64.  
  65. #if 0
  66. /* The graphics context.  */
  67. GC default_gc;
  68. #endif
  69.  
  70. /* Windows manipulated by this package.  */
  71.  
  72. static Window icon_window;
  73. static Widget main_widget;
  74. static Widget containing_widget;
  75. static Widget source_name_widget;
  76. static Widget source_text_widget;
  77. static Widget exec_name_widget;
  78. static Widget button_box_widget;
  79.  
  80. /* Source text display.  */
  81.  
  82. static struct symtab *source_window_symtab = 0;
  83.  
  84. /* Forward declarations */
  85.  
  86. static Widget create_text_widget ();
  87.  
  88. /* Display an appropriate piece of source code in the source window.  */
  89.  
  90. xgdb_display_source ()
  91. {
  92.   char *filename;
  93.   static Arg labelArgs[1];
  94.   int linenumbers_changed = 0;
  95.   static int new = 1;
  96.  
  97.   struct symtab_and_line get_selected_frame_sal ();
  98.   struct symtab_and_line sal;
  99.   struct frame_info *fi;
  100.  
  101.   /* Do nothing if called before we are initialized or when there
  102.      is nothing to show.   */
  103.  
  104.   if (!containing_widget || !selected_frame) return;
  105.  
  106.   /* Get the symtab and line number of the selected frame.  */
  107.  
  108.   fi = get_frame_info (selected_frame);
  109.   sal = find_pc_line (fi->pc, fi->next_frame);
  110.  
  111.   /* Strictly this is wrong, but better than a blank display */
  112.  
  113.   if (sal.symtab == NULL) 
  114.     {
  115.       sal.symtab = current_source_symtab;
  116.       /* current_source_line may be off by a small number like 4 */
  117.       sal.line = current_source_line;
  118.     }
  119.  
  120.   /* Do a path search and get the exact filename of this source file.
  121.      Also scan it and find its source lines if not already done.  */
  122.  
  123.   if (sal.symtab)
  124.     linenumbers_changed = get_filename_and_charpos (sal.symtab, sal.line,
  125.                             &filename);
  126.  
  127.   if (!filename) sal.symtab = NULL;
  128.  
  129.   /* If the source window may be wrong, destroy it (and make a new one).  */
  130.  
  131.   if (linenumbers_changed || source_window_symtab != sal.symtab)
  132.     {
  133.       static Arg fileArgs[1];
  134.       XtTextSource    src;
  135.       new = 1;
  136.       source_window_symtab = sal.symtab;
  137.  
  138.       src = XtTextGetSource(source_text_widget);
  139.       XtDiskSourceDestroy(src);
  140.       
  141.       XtSetArg (fileArgs[0], XtNfile, filename);
  142.       src = XtDiskSourceCreate(source_text_widget->core.parent, fileArgs, 1);
  143.       XtTextSetSource(source_text_widget, src, 0);
  144.  
  145.       XtSetArg (labelArgs[0], XtNlabel,
  146.         filename ? filename : "No source displayed.");
  147.       XtSetValues (source_name_widget, labelArgs, XtNumber (labelArgs));
  148.       if (filename) free (filename);
  149.     }
  150.  
  151.   /* Update display and cursor positions as necessary.
  152.      Cursor should be placed on line sal.line.  */
  153.  
  154.   {
  155.     static int top_line_number, bottom_line_number;
  156.     int current_top;
  157.     Arg textArgs[1];
  158.  
  159.     if (! new)
  160.       {
  161.     int new_top;
  162.  
  163.     /* Get positions of start of display, and caret */
  164.     XtSetArg (textArgs[0], XtNdisplayPosition, NULL);
  165.     XtGetValues (source_text_widget, textArgs, XtNumber (textArgs));
  166.     new_top = source_charpos_line (source_window_symtab,
  167.                        (int) textArgs[0].value);
  168.     bottom_line_number += new_top - top_line_number;
  169.     top_line_number = new_top;
  170.       }
  171.  
  172.     /* If appropriate, scroll the text display.  */
  173.     if (sal.line < top_line_number
  174.     || sal.line > bottom_line_number
  175.     || new)
  176.       {
  177.     /* yes, these magic numbers are ugly, but I don't know how
  178.      * to get the height of a text widget in a V11-portable way
  179.      */
  180.     top_line_number = (sal.line > 15) ? sal.line - 15 : 0;
  181.     bottom_line_number = top_line_number + 35;
  182.       
  183.     XtSetArg (textArgs[0], XtNdisplayPosition,
  184.           source_line_charpos (source_window_symtab, top_line_number));
  185.     XtSetValues (source_text_widget, textArgs, XtNumber (textArgs));
  186.       }
  187.  
  188.     /* Set the text display cursor position within the text.  */
  189.  
  190.     XtSetArg (textArgs[0], XtNinsertPosition, 
  191.           source_line_charpos (source_window_symtab, sal.line));
  192.     XtSetValues (source_text_widget, textArgs, XtNumber (textArgs));
  193.   }
  194. }
  195.  
  196. /* Display FILENAME in the title bar at bottom of window.  */
  197.  
  198. xgdb_display_exec_file (filename)
  199.      char *filename;
  200. {
  201.   static Arg labelArgs[1];
  202.  
  203.   XtSetArg (labelArgs[0], XtNlabel, filename);
  204.   XtSetValues (exec_name_widget, labelArgs, XtNumber (labelArgs));
  205. }
  206.  
  207. /* Do any necessary prompting, etc.  */
  208.  
  209. static char *prompt_string;
  210.  
  211. static void
  212. print_prompt ()
  213. {
  214.   if (prompt_string)
  215.     printf ("%s", prompt_string);
  216.   fflush (stdout);
  217. }
  218.  
  219. /* Handlers for buttons.  */
  220.  
  221. /* Subroutine used by "print" and "print*" buttons.
  222.    STARFLAG is 1 for print*, 0 for print.
  223.    Get the "selection" from X and use it as the operand of a print command.  */
  224.  
  225. static void
  226. print_button(w, starflag, call_data)
  227. Widget    w;
  228. int    starflag;
  229. caddr_t    call_data;
  230. {
  231.   int selected_length;
  232.   char *selected_text;
  233.   char *cmd = starflag ? "print * " : "print ";
  234.   register int cmdlen = strlen (cmd);
  235.   
  236.   selected_text = XFetchBytes (screen_display, &selected_length);
  237.   if (selected_length)
  238.     {
  239.       char *line = xmalloc (cmdlen + selected_length + 1);
  240.       strcpy (line, cmd);
  241.       strncpy (line + cmdlen, selected_text, selected_length);
  242.       line[cmdlen + selected_length] = 0;
  243.  
  244.       execute_command (line, 0);
  245.  
  246.       free (selected_text);
  247.       free (line);
  248.     }
  249.  
  250.   print_prompt ();
  251. }
  252.  
  253.  
  254. /* Subroutine used by "stop at" and "go till" buttons.
  255.    Set a breakpoint at the position indicated by the "selection"
  256.    in the source window, and, if RUNFLAG is nonzero, continue.  */
  257.  
  258. static void
  259. breakpoint_button(w, runflag, call_data)
  260. Widget    w;
  261. int    runflag;
  262. caddr_t    call_data;
  263. {
  264.   XtTextPosition start, finish;
  265.   
  266.   XtTextGetSelectionPos (source_text_widget, &start, &finish);
  267.   if (!source_window_symtab)
  268.     printf ("No source file displayed.\n");
  269.   else
  270.     {
  271.       set_breakpoint (source_window_symtab, 
  272.               source_charpos_line (source_window_symtab, start),
  273.               runflag);
  274.       if (runflag)
  275.     {
  276.       cont_command (0, 1);
  277.       xgdb_display_source ();
  278.     }
  279.     }
  280.   print_prompt ();
  281. }
  282.  
  283. /* decide if a character is trash */
  284. static int
  285. garbage (c)
  286.      char c;
  287. {
  288.   if ('a' <= c && c <= 'z') return 0;
  289.   if ('A' <= c && c <= 'Z') return 0;
  290.   if ('0' <= c && c <= '9') return 0;
  291.   if (c == '_') return 0;
  292.   return 1;
  293. }
  294.  
  295. /* Set a breakpoint at the place specified by the "selection" in X.  */
  296.  
  297. static void
  298. explicit_breakpoint_button ()
  299. {
  300.   int selected_length;
  301.   char *selected_text;
  302.  
  303.   selected_text = XFetchBytes (screen_display, &selected_length);
  304.   if (selected_length)
  305.     {
  306.       char *line = (char *) xmalloc (selected_length + 6);
  307.       register char *p, *sp, *end;
  308.  
  309.       strcpy (line, "break ");
  310.  
  311.       /* Copy selection but exclude "garbage" characters.  */
  312.  
  313.       p = selected_text;
  314.       end = p + selected_length;
  315.       sp = line + strlen (line);
  316.  
  317.       while (garbage (*p) && p != end) p++;
  318.       while (!garbage (*p) && p != end)
  319.     *sp++ = *p++;
  320.       *sp = 0;
  321.  
  322.       execute_command (line, 0);
  323.       free (selected_text);
  324.       free (line);
  325.     }
  326.   print_prompt ();
  327. }
  328.  
  329.  
  330. static void
  331. do_command(w, command, call_data)
  332. Widget    w;
  333. char    *command;
  334. caddr_t    call_data;
  335. {
  336.   char *copy = (char *) xmalloc (strlen (command) + 1);
  337.   strcpy (copy, command);
  338.   execute_command (copy, 0);
  339.   xgdb_display_source ();
  340.   print_prompt ();
  341.   free (copy);
  342. }
  343.  
  344. static void
  345. redisplay_button()
  346. {
  347.     xgdb_display_source();
  348. }
  349.  
  350. /* Define and display all the buttons.  */
  351.  
  352. static void
  353. addbutton (parent, name, function, closure)
  354. Widget    parent;
  355. char    *name;
  356. void    (*function) ();
  357. caddr_t    closure;
  358. {
  359.     static    XtCallbackRec    Callback[] = {
  360.         {NULL, (caddr_t)NULL},
  361.         {NULL, (caddr_t)NULL},
  362.     };
  363.     static    Arg    commandArgs[] = {
  364.         {XtNlabel, (XtArgVal)NULL},
  365.         {XtNcallback, (XtArgVal)Callback},
  366.     };
  367.  
  368.     Callback[0].callback = (XtCallbackProc)function;
  369.         Callback[0].closure = (caddr_t)closure;
  370.     commandArgs[0].value = (XtArgVal)name;
  371.     XtCreateManagedWidget (name, commandWidgetClass, parent,
  372.                    commandArgs, XtNumber(commandArgs));
  373. }
  374.  
  375. /* Create the button windows and store them in `buttons'.  */
  376.  
  377. static void
  378. create_buttons (parent)
  379.      Widget parent;
  380. {
  381.   addbutton (parent, "run", do_command, "run");
  382.   addbutton (parent, "quit", do_command, "quit");
  383.  
  384.   addbutton (parent, "break in", explicit_breakpoint_button, NULL);
  385.   addbutton (parent, "break at", breakpoint_button, 0);
  386.   addbutton (parent, "go until", breakpoint_button, 1);
  387.  
  388.   addbutton (parent, "print", print_button, 0);
  389.   addbutton (parent, "print*", print_button, 1);
  390.  
  391.   addbutton (parent, "next", do_command, "next");
  392.   addbutton (parent, "step", do_command, "step");
  393.   addbutton (parent, "cont", do_command, "cont");
  394.   addbutton (parent, "finish", do_command, "finish");
  395.   
  396.   addbutton (parent, "up", do_command, "up");
  397.   addbutton (parent, "down", do_command, "down");
  398.  
  399.   addbutton (parent, "redisplay", redisplay_button, NULL);
  400. }
  401.  
  402. /* Create a "label window" that just displays the string LABEL.  */
  403.  
  404. static Widget
  405. create_label (name, label)
  406.      char *name, *label;
  407. {
  408.   static Arg labelArgs[2];
  409.   
  410.   XtSetArg (labelArgs[0], XtNname, name);
  411.  
  412.   XtSetArg (labelArgs[1], XtNlabel, label);
  413.   return XtCreateManagedWidget ("label", labelWidgetClass, containing_widget,
  414.              labelArgs, XtNumber (labelArgs));
  415. }
  416.  
  417. /* Create a subwindow of PARENT that displays and scrolls the contents
  418.    of file FILENAME.  */
  419.  
  420. static Widget
  421. create_text_widget (parent, filename)
  422.      Widget parent;
  423.      char *filename;
  424. {
  425.   static Arg fileArgs[3];
  426.   XtTextSource src;
  427.   XtTextSink   sink;
  428.   Widget text_widget;
  429.  
  430.   text_widget = XtCreateManagedWidget ("disk", textWidgetClass,
  431.                        parent, NULL, 0);
  432.  
  433.   XtSetArg (fileArgs[0], XtNfile, filename);
  434.   src = XtDiskSourceCreate(parent, fileArgs, 1);
  435.   sink = XtAsciiSinkCreate(parent, NULL, 0);
  436.   
  437.   XtSetArg (fileArgs[0], XtNtextOptions, scrollVertical);
  438.   XtSetArg (fileArgs[1], XtNtextSource, src);
  439.   XtSetArg (fileArgs[2], XtNtextSink, sink);
  440.   XtSetValues (text_widget, fileArgs, XtNumber (fileArgs));
  441.   return text_widget;
  442. }
  443.  
  444. /* Entry point to create the widgets representing our display.  */
  445.  
  446. int
  447. xgdb_create_window ()
  448. {
  449.   static Arg frameArgs[]= {
  450.       {XtNwidth, (XtArgVal) 600},
  451.       {XtNheight, (XtArgVal) 700},
  452.   };
  453.   {
  454.     char *dummy1[2];
  455.     int dummy2 = 1;
  456.     
  457.     dummy1[0] = "xgdb";
  458.     dummy1[1] = NULL;
  459.     main_widget = XtInitialize ("xgdb", "XGdb", 0, 0, &dummy2, dummy1);
  460.   }
  461.  
  462.   screen_display = XtDisplay(main_widget);
  463.   
  464.   /* Create the containing_widget.  */
  465.  
  466.   containing_widget = XtCreateManagedWidget ("frame", vPanedWidgetClass, main_widget,
  467.                       frameArgs, XtNumber (frameArgs));
  468.   /* Create source file name window and add to containing_widget */
  469.   source_name_widget
  470.     = create_label ("Source File", "No source file yet.");
  471.  
  472.   /* Create exec file name window and add */
  473.   exec_name_widget = create_label ("Executable", "No executable specified.");
  474.  
  475.   /* Create window full of buttons.  */
  476.   button_box_widget = XtCreateManagedWidget ("buttonbox", boxWidgetClass,
  477.                       containing_widget, NULL, 0);
  478.   create_buttons (button_box_widget);
  479.  
  480.   /* Create an empty source-display window and add to containing_widget */
  481.   source_text_widget = create_text_widget (containing_widget, "/dev/null");
  482.  
  483.   XSync(screen_display, 0);
  484.   XtRealizeWidget(main_widget);
  485.   
  486. #if 0
  487.   default_gc = XCreateGC (screen_display, XtWindow(containing_widget), 0, NULL);
  488.   /* Create icon window.  */
  489.   {
  490.     static Arg iconArgs[2];
  491.     void (*compiler_bug) () = deiconify_button;
  492.     XtSetArg (iconArgs[0], XtNlabel, "(gdb)");
  493.     XtSetArg (iconArgs[1], XtNfunction, compiler_bug);
  494.     icon_window = XtCreateWidget ("Icon", commandWidgetClass, 
  495.                    iconArgs, XtNumber (iconArgs));
  496.     XMoveWindow (screen_display, icon_window, 100, 100);    /* HACK */
  497.     XSetIconWindow (screen_display, containing_widget, icon_window);
  498.   }
  499.  
  500.   /* Now make the whole thing appear on the display.  */
  501.   {
  502.     Pixmap pm1, pm2;
  503.     XImage image;
  504.     Cursor curse;
  505.  
  506.     image.width = gdb_width;
  507.     image.height = gdb_height;
  508.     image.xoffset = 0;
  509.     image.format = XYBitmap;
  510.     image.byte_order = LSBFirst;
  511.     image.bitmap_unit = 16;
  512.     image.bitmap_bit_order = LSBFirst;
  513.     image.depth = 1;
  514.     image.bytes_per_line = 2;
  515.     image.bits_per_pixel = 1;
  516.  
  517.     pm1 = XCreatePixmap (screen_display, DefaultScreen (screen_display),
  518.              gdb_width, gdb_height, 1);
  519.     pm2 = XCreatePixmap (screen_display, DefaultScreen (screen_display),
  520.              gdb_width, gdb_height, 1);
  521.  
  522.     image.data = (char *) gdb_bits;
  523.     XPutImage (screen_display, pm1, default_gc, &image, 0, 0, 0, 0,
  524.            gdb_width, gdb_height);
  525.  
  526.     image.data = (char *) gdb_mask_bits;
  527.     XPutImage (screen_display, pm2, default_gc, &image, 0, 0, 0, 0,
  528.            gdb_width, gdb_height);
  529.  
  530.     curse = XCreatePixmapCursor (screen_display, pm1, pm2,
  531.                  BlackPixel (screen_display,
  532.                          DefaultScreen (screen_display)),
  533.                  WhitePixel (screen_display,
  534.                          DefaultScreen (screen_display)),
  535.                  gdb_x_hot, gdb_y_hot);
  536.  
  537.     XFreePixmap (screen_display, pm1);
  538.     XFreePixmap (screen_display, pm2);
  539.  
  540.     XDefineCursor (screen_display, containing_widget, curse);
  541.     XDefineCursor (screen_display, icon_window, curse);
  542.   }
  543. #endif 0
  544.  
  545.   XFlush (screen_display);
  546.  
  547.   return 1;
  548. }
  549.  
  550. /* xgdb_dispatch -- Loop, dispatching on window events,
  551.    until data is available on FP (which is normally stdin).
  552.    Then return, so the data on FP can be processed.  */
  553.  
  554. void
  555. xgdb_dispatch (fp)
  556.      FILE *fp;
  557. {
  558.   int inmask = 1 << fileno (fp);
  559.   int xmask = 1 << ConnectionNumber (screen_display);
  560.   int rfds = 0;
  561.   int nfds;
  562.   XEvent ev;
  563.   int pend;
  564.   
  565.   while (! (rfds & inmask))
  566.     {
  567.       pend = XPending (screen_display);
  568.       if (!pend)
  569.     {
  570.       rfds = inmask | xmask;
  571.       /* this isn't right for 4.3 but it works 'cuz of 4.2 compatibility */
  572.       nfds = select (32, &rfds, 0, 0, (struct timeval *) 0);
  573.     }
  574.       if (pend || rfds & xmask)
  575.     {
  576.       XNextEvent (screen_display, &ev);
  577.       XtDispatchEvent (&ev);
  578.     }
  579.     }
  580. }  
  581.  
  582. /* If we use an X window, the GDB command loop is told to call this function
  583.  
  584.    before reading a command from stdin.
  585.    PROMPT is saved for later use so buttons can print a prompt-string.  */
  586.  
  587. void
  588. xgdb_window_hook (infile, prompt)
  589.      FILE *infile;
  590.      char *prompt;
  591. {
  592.   prompt_string = prompt;
  593.   xgdb_display_source ();
  594.   xgdb_dispatch (infile);
  595. }
  596.  
  597. _initialize_xgdb ()
  598. {
  599.   extern void (*window_hook) ();
  600.   extern int inhibit_windows;
  601.  
  602.   if (getenv ("DISPLAY") && ! inhibit_windows)
  603.     {
  604.       if (xgdb_create_window ())
  605.     window_hook = xgdb_window_hook;
  606.  
  607.       specify_exec_file_hook (xgdb_display_exec_file);
  608.     }
  609. }
  610.  
  611.  
  612.